home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Imaging Engine / CRDManagement.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  14.7 KB  |  512 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        CRDManagement.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          This file contains code to manage color rendering dictionaries
  6.                          for PostScript color matching.
  7.  
  8.      Version:    Technology:    Quickdraw GX 1.1.x
  9.       
  10.      Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  11. */
  12.  
  13. #include "GXToPSBuildConfig.h"
  14. #include <GXGraphics.h>
  15. #include "GXGraphicsPriv.h"
  16. #include <GXEnvironment.h>
  17. #include "GXToPostScript.h"
  18. #include "IOUtilities.h"
  19. #include "RDUtil.h"
  20. #include "FontHandler.h"
  21. #include "PublicPostScriptIE.h"
  22. #include "private.h"
  23. #include "PSIEResources.h"
  24. #include "GXErrors.h"
  25. #include "ShapeUtilities.h"
  26.  
  27. #include <CMICCProfile.h>
  28. #include <CMApplication.h>
  29.  
  30. #ifdef resumeLabel
  31.     #undef resumeLabel
  32. #endif
  33. #define resumeLabel(exception)
  34.  
  35.  
  36.  
  37.  
  38. /*--------------------------------CRD Downloading stuff-------------------------------------------*/
  39.  
  40. /*********************************
  41.  
  42.     Streaming function for ICC Profile streaming stuff.
  43.     This function is used for sending postscript data for 
  44.     ICC profiles.
  45.     
  46.     The imaging engine globals are passed as the refcon.
  47.     
  48.     command:        ColorSync stream command.
  49.     size:                how many bytes to write (by reference)
  50.     data:                pointer to bytes to write.
  51.     hIEGlobals: Imaging engine globals.
  52.     
  53. *********************************/
  54. pascal OSErr    ICCProfileStreamProc(long command, long *size, void *data, TIEGlobalsHdl hIEGlobals)
  55.     {
  56.         OSErr            status = noErr;
  57.         
  58.         switch(command) {
  59.  
  60.             case cmCloseSpool:
  61.                     #if DEBUGLEVEL > 0
  62.                         if (*size > 0)
  63.                             dprintf(trace, "Funny, size on close is non-zero.  Ignoring data");
  64.                         status = (*hIEGlobals)->psDevice->BufferData("\n%- End of ColorSync streamed data\n", 35, gxNoBufferOptions);
  65.                     #endif
  66.                     nrequire(status, failed_close);
  67.                     break;
  68.  
  69.             case cmOpenWriteSpool:
  70.                 status = RDFlushBuffer((*hIEGlobals)->rdMap);
  71.                 nrequire(status, failed_rdFlush);
  72.                 #if DEBUGLEVEL > 0
  73.                     if (*size > 0)
  74.                         dprintf(trace, "Funny, size on open is non-zero.  Ignoring data");
  75.                     status = (*hIEGlobals)->psDevice->BufferData("\n%- Start of ColorSync streamed data\n", 37, gxNoBufferOptions);
  76.                     nrequire(status, failed_open);
  77.                 #endif
  78.                 break;
  79.  
  80.             case cmWriteSpool:
  81.                 if (*size > 0)
  82.                     status = (*hIEGlobals)->psDevice->BufferData((char*)data, *size, gxNoBufferOptions);            // hexification should be handled by ColorSync itself.
  83.                 nrequire(status, failed_write);
  84.                 break;
  85.  
  86.  
  87.             case cmReadSpool:
  88.             case cmOpenReadSpool:
  89.             default:
  90.                 #if DEBUGLEVEL > 0
  91.                     dprintf(notrace, "Unsupported profile stream command: %d", command);
  92.                 #endif
  93.                 status = colorSpace_out_of_range;  /* for lack of something better to return - this should never happen anyway */
  94.         
  95.         }//end switch
  96.  
  97. failed_write:
  98. failed_close:
  99. failed_open:
  100. failed_rdFlush:
  101.  
  102.         return(status);
  103.         
  104.     }//ICCProfileStreamProc
  105.  
  106.  
  107.  
  108. /*********************************
  109.  
  110.     Another Streaming function for ICC Profile streaming stuff.
  111.         This one is used to load a string with the rendering inent name only.
  112.     
  113.     command:        ColorSync stream command.
  114.     size:                how many bytes to write (by reference)
  115.     data:                pointer to bytes to write.
  116.     hIEGlobals: Imaging engine globals.
  117.     
  118. *********************************/
  119. pascal OSErr    NameStreamProc(long command, long *size, void *data, Str255 name);
  120. pascal OSErr    NameStreamProc(long command, long *size, void *data, Str255 name)
  121.     {
  122.         OSErr                        status = noErr;
  123.         unsigned long        length;
  124.  
  125.         switch(command) {
  126.         
  127.             case cmCloseSpool:
  128.                     /* Rewind length to eliminate trailing white spaces */
  129.                     length = (unsigned char)name[0];
  130.                     while ( (length > 0) && ((name[length] == ' ') || (name[length] == '\r') || (name[length] == '\n')  ) )    
  131.                         --length;
  132.                     
  133.                     name[0] = length;
  134.                     
  135.                     break;
  136.  
  137.             case cmOpenWriteSpool:
  138.                 name[0] = 0;                        // Initialize the length.
  139.                 break;
  140.  
  141.             case cmWriteSpool:
  142.                 length = (unsigned char)name[0];
  143.                 if ( (length + *size) >= 100 )
  144.                     *size = 100 - length;
  145.                     
  146.                 BlockMoveData(data, &(name[length+1]), *size);
  147.                 length += *size;
  148.                 name[0] = length;
  149.  
  150.                 break;
  151.  
  152.             case cmReadSpool:
  153.             case cmOpenReadSpool:
  154.             default:
  155.                 #if DEBUGLEVEL > 0
  156.                     dprintf(notrace, "Unsupported profile stream command: %d", command);
  157.                 #endif
  158.                 status = colorSpace_out_of_range;  /* for lack of something better to return - this should never happen anyway */
  159.         
  160.         }//end switch
  161.  
  162.         return(status);
  163.         
  164.     }//NameStreamProc
  165.  
  166.  
  167. /*------------------------------------------------------------------------------------------*/
  168.  
  169.  
  170. /***
  171.     The imaging engine will maintain a list of tags on the device profile.
  172.     Each tag will contain info for the CRD of a particular rendering intent
  173.     requested.
  174. ***/
  175. // Tag type for device profile CRD information
  176. #define crdInfoTagType 'pscd'
  177.  
  178. typedef struct {
  179.  
  180.     /* 
  181.         intent and flags will key our database.  Note, this database key will return
  182.         false positive should there ever be a CMM that would download a different CRD for the same
  183.         dest profile         for a source profile that had the same intent and flags as another source profile
  184.         Steve Swen (Lead ColorSync guy) assures me that this is sufficient 11/1/96.
  185.     */
  186.     
  187.     unsigned long        flags;                            // profile flags this CRD is for?
  188.     unsigned long        renderingIntent;        // Which rendering intent is this for?
  189.  
  190.     
  191.     unsigned char        psName[129];                // this will be the PostScript name, as pascal string
  192.     unsigned long        vmUsage;                        // How much VM does it use?
  193.     Boolean                    onPrinter;                    // Is it already downloaded?
  194.     Boolean                    isDocLevel;                    // Is it downloaded document level?
  195.  
  196. } TcrdInfoRec;
  197.  
  198.  
  199.  
  200.  
  201. /************************
  202.  
  203.     Routine constructs the PostScript name for the CRD
  204.     
  205.     Name will be the rendering intent appended with "Mac.none".
  206.       This seems to be what the LaserWriter 8.x driver does.
  207.         
  208.         Note, keep this in sync with code in GXFindCRDName in Level2ColorProcs.ps
  209.     
  210. *************************/
  211. OSErr ConstructCRDpsName(CMProfileRef sourceProfile, Str255 name);
  212. OSErr ConstructCRDpsName(CMProfileRef sourceProfile, Str255 name)
  213.     {
  214.         OSErr            status;
  215.     
  216.         Boolean                preferredCMMNotFound;    
  217.         CMFlattenUPP    streamProc = NewCMFlattenProc(NameStreamProc);                 // note assuming this segment stays locked since it is in call-chain.
  218.         
  219.         /* First put the rendering intent at the beginning of name */
  220.         
  221.         status = CMGetPS2ColorRenderingIntent(sourceProfile,  cmPS7bit, streamProc, name, &preferredCMMNotFound);
  222.         DisposeRoutineDescriptor(streamProc);
  223.         nrequire(status, failed_cs2Stream);
  224.         
  225.         /* Now append suffix to it. */
  226.  
  227.         BlockMoveData(".Mac.none", &(name[name[0]+1]), 9);
  228.         name[0] += 9;
  229.         
  230. failed_cs2Stream:
  231.         return(status);
  232.         
  233.     }//ConstructCRDpsName
  234.  
  235. /**********************************************
  236.  
  237.     FindOrAddIntentInfoToProfile:
  238.     
  239.     This routine retrieves the tag on the gx-profile
  240.     containing the CRD info for the desired
  241.     rendering intent.
  242.     
  243. ***********************************************/
  244. OSErr FindOrAddIntentInfoToProfile(gxColorProfile theGXDstProfile, CMProfileRef sourceProfile, gxTag *crdInfoTag);
  245. OSErr FindOrAddIntentInfoToProfile(gxColorProfile theGXDstProfile, CMProfileRef sourceProfile, gxTag *crdInfoTag)
  246.     {
  247.         OSErr                                    status;
  248.         long                                    numCRDsSoFar;
  249.         long                                    idx;
  250.         Boolean                                foundIt = false;
  251.         TcrdInfoRec                        crdInfo;
  252.         TcrdInfoRec*                    crdInfoPtr;
  253.         CMProfileRef                    theDstProfile;
  254.         CMAppleProfileHeader    profHeader;
  255.         Boolean                                prefferendNotFound;
  256.         
  257.         status = CMGetProfileHeader(sourceProfile, &profHeader);
  258.         nrequire(status, failed_getheader);
  259.         
  260.         *crdInfoTag = nil;
  261.         numCRDsSoFar =     GXGetColorProfileTags(theGXDstProfile, crdInfoTagType, 1, gxSelectToEnd, nil);
  262.         
  263.         #if DEBUGLEVEL > 0
  264.             dprintf(trace, "# of CRDs databased so far on dest profile: %d", numCRDsSoFar);
  265.         #endif
  266.         
  267.         /* Search all the tags on the profile for the one we want */
  268.         for (idx = 1; idx <= numCRDsSoFar; ++idx) {
  269.         
  270.             GXGetColorProfileTags(theGXDstProfile, crdInfoTagType, idx, 1, crdInfoTag);
  271.             crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(*crdInfoTag, nil);
  272.             
  273.             /* we found it, exit the loop */
  274.             if ( (crdInfoPtr->renderingIntent == profHeader.cm2.renderingIntent)  && (crdInfoPtr->flags == profHeader.cm2.flags) ) {
  275.                 foundIt = true;
  276.                 break;
  277.             }//end if
  278.  
  279.             nrequire(status = GXGetGraphicsError(nil), failed_gettag);
  280.                 
  281.         }//end for
  282.         
  283.         /* If we didn't find the tag for our rendering intent in the profile, make it and add it */
  284.         
  285.         if (!foundIt) {
  286.  
  287.             #if DEBUGLEVEL > 0
  288.                 dprintf(trace, "CRD hasn't been added to dest profile database yet, adding now");
  289.             #endif
  290.             
  291.             theDstProfile = GXGetColorProfileReference(theGXDstProfile);
  292.             
  293.             crdInfo.renderingIntent = profHeader.cm2.renderingIntent;
  294.             crdInfo.flags = profHeader.cm2.flags;
  295.             crdInfo.onPrinter = false;
  296.             crdInfo.isDocLevel = false;
  297.             status = ConstructCRDpsName(sourceProfile, crdInfo.psName);
  298.             nrequire(status, failed_name);
  299.             
  300.             status = CMGetPS2ColorRenderingVMSize(sourceProfile, theDstProfile, &(crdInfo.vmUsage), &prefferendNotFound);
  301.             nrequire(status, failed_VM);
  302.             
  303.             *crdInfoTag = GXNewTag(crdInfoTagType, sizeof(TcrdInfoRec), &crdInfo);
  304.             GXSetColorProfileTags(theGXDstProfile, crdInfoTagType, 0, 0, 1, crdInfoTag);
  305.             GXDisposeTag(*crdInfoTag);            // The profile owns this now, so decrement the owner count.
  306.             
  307.             status = GXGetGraphicsError(nil);            // just checking.
  308.             nrequire(status, failed_makeTag);
  309.             
  310.         }//end if
  311.  
  312. failed_makeTag:
  313. failed_VM:
  314. failed_name:
  315. failed_gettag:
  316. failed_getheader:
  317.  
  318.         return(status);
  319.         
  320.     }//FindOrAddIntentInfoToProfile
  321.     
  322.     
  323. //<FF>
  324. /**********************************************
  325.  
  326.     MakeCRDAvailable:
  327.     
  328.     This function ensures that the desired CRD is available
  329.     on the printer.  If a destination profile other than the printers
  330.     default (indicated by the device profile being the zero length
  331.     profile) is specified, then this routine will 
  332.     download the CRD if it has not already been downloaded
  333.     prior to this request
  334.     
  335.     
  336.     sourceProfile:                The profile of the source data we need for which we need the correct
  337.                                                 device profile's CRD
  338.                                                 
  339. ***********************************************/
  340. OSErr MakeCRDAvailable(TIEGlobalsHdl hIEGlobals, CMProfileRef sourceProfile)
  341.     {
  342.         OSErr                            status = noErr;    
  343.         gxColorProfile        destProfileGX;
  344.         CMProfileRef            destProfile;
  345.         gxTag                            infoTag;
  346.         TcrdInfoRec                *crdInfoPtr;
  347.         TRDParams*                pRDParams = (*hIEGlobals)->pRDParams;
  348.         
  349.         destProfileGX = (*hIEGlobals)->params.devCProfile;
  350.         destProfile = GXGetColorProfileReference( destProfileGX );
  351.                 
  352.         if ( destProfile != nil ) {
  353.     
  354.             /* non-zero length ICC profile, make sure the CRD is available on the printer */
  355.             
  356.             // Find our tag on the gxProfile reference for this rendering intent, or make one.
  357.             
  358.             status = FindOrAddIntentInfoToProfile(destProfileGX, sourceProfile, &infoTag);
  359.             nrequire(status, failed_findInfo);
  360.             
  361.             // Now, download the CRD specified by the tag, if it is not already there.
  362.             
  363.             GXLockTag(infoTag);
  364.             crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(infoTag, nil);
  365.             
  366.             if ( !crdInfoPtr->onPrinter) {
  367.             
  368.                 /* Download and name the CRD */            
  369.  
  370.                 Boolean                preferredCMMNotFound;    
  371.                 CMFlattenUPP    streamProc = NewCMFlattenProc(ICCProfileStreamProc);                 // note assuming this segment stays locked since it is in call-chain.
  372.  
  373.                 /* Download the CRD into global VM */
  374.                 
  375.                 pRDParams->resIndex = kSetGlobalVM;                                // note, this leaves global state on stack.
  376.                 status = RDResPrintf(pRDParams, (long)true);
  377.                 nrequire(status, failed_global_on);
  378.  
  379.                 /* do the actual download */
  380.                 
  381.                 status = CMGetPS2ColorRendering(sourceProfile, destProfile, ((*hIEGlobals)->params.renderOptions & gxNeedsHexOption) ? cmPS7bit : cmPS8bit,
  382.                                                                                 streamProc, hIEGlobals, &preferredCMMNotFound);
  383.                                                                                 
  384.                 DisposeRoutineDescriptor(streamProc);
  385.                 nrequire(status, failed_streamCRD);
  386.                 
  387.                 /* Now define the CRD resource */
  388.  
  389.                 pRDParams->resIndex = kDefineCRD;
  390.                 status = RDResPrintf(pRDParams, crdInfoPtr->psName);
  391.                 nrequire(status, failed_defineCRD);
  392.                 
  393.                 pRDParams->resIndex = kRestoreGlobalVM;                
  394.                 status = RDResPrintf(pRDParams);
  395.                 nrequire(status, failed_global_off);
  396.  
  397.                 crdInfoPtr->onPrinter = true;
  398.             
  399.             } else {
  400.             
  401.                 #if DEBUGLEVEL > 0
  402.                     dprintf(trace, "Requested CRD is already on printer: %P", crdInfoPtr->psName);
  403.                 #endif
  404.             
  405.             }//end if
  406.  
  407. failed_global_off:
  408. failed_defineCRD:
  409. failed_streamCRD:
  410. failed_global_on:
  411.  
  412.             GXUnlockTag(infoTag);
  413.                         
  414.         }//end if
  415.  
  416.  
  417. failed_findInfo:        
  418.         return(status);
  419.         
  420.     }//MakeCRDAvailable
  421.  
  422.  
  423.  
  424.  
  425. /**********************************************
  426.  
  427.     RemoveDownloadedCRDs:
  428.  
  429.     This function removes from PostScript VM any CRDs
  430.     that were downloaded for the device profile.
  431.     
  432.     This routine should be called at the end of each page
  433.     when generating Page Independent PostScript.
  434.                                                 
  435. ***********************************************/
  436. OSErr RemoveDownloadedCRDs(TIEGlobalsHdl hIEGlobals)
  437.     {
  438.         OSErr                            status = noErr;    
  439.         gxColorProfile        destProfileGX;
  440.         gxTag                            infoTag;
  441.         TcrdInfoRec                *crdInfoPtr;
  442.         long                            idx, count;
  443.         TRDParams*                pRDParams = (*hIEGlobals)->pRDParams;
  444.         Boolean                        tagLocked = false;
  445.         
  446.         destProfileGX = (*hIEGlobals)->params.devCProfile;
  447.         
  448.         if (destProfileGX == nil)        
  449.             return noErr;
  450.     
  451.         count =    GXGetColorProfileTags(destProfileGX, crdInfoTagType, 1, gxSelectToEnd, nil);
  452.         if (count > 0) {
  453.         
  454.             #if DEBUGLEVEL > 0    
  455.                 status = RDFlushBuffer((*hIEGlobals)->rdMap);
  456.                 if (status == noErr)
  457.                     status = (*hIEGlobals)->psDevice->BufferData("\n%- Cleaning up downloaded CRDs\n", 32, gxNoBufferOptions);
  458.                     
  459.                 nrequire(status, failed_debuggingComment);
  460.             #endif
  461.  
  462.             /* Since CRD's are defined in global-VM, undefine them in global-VM too! */
  463.  
  464.             pRDParams->resIndex = kSetGlobalVM;                                // note, this leaves global state on stack.
  465.             status = RDResPrintf(pRDParams, (long)true);
  466.             nrequire(status, failed_global_on);
  467.  
  468.             /* Loop on each CRD associated with the device profile */
  469.             
  470.             for (idx = 1; idx <= count; ++idx) {
  471.             
  472.                 GXGetColorProfileTags(destProfileGX, crdInfoTagType, idx, 1, &infoTag);
  473.                 GXLockTag(infoTag);
  474.                 tagLocked = true;
  475.                 crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(infoTag, nil);
  476.                 
  477.                 /* If the CRD has been downloaded, but not for whole document, undefine it from VM */
  478.     
  479.                 if (crdInfoPtr->onPrinter && (!crdInfoPtr->isDocLevel) ) {
  480.                 
  481.                     pRDParams->resIndex = kUndefineCRD;
  482.                     status = RDResPrintf(pRDParams, crdInfoPtr->psName);
  483.                     nrequire(status, failed_undefine);
  484.                     
  485.                     crdInfoPtr->onPrinter = false;                    // mark it undlownloaded.
  486.                 
  487.                 }//end if
  488.                 
  489.                 GXUnlockTag(infoTag);
  490.                 tagLocked = false;
  491.     
  492.             }//end for
  493.     
  494.             /* Restore global-vm state */
  495.         
  496.             pRDParams->resIndex = kRestoreGlobalVM;
  497.             status = RDResPrintf(pRDParams);
  498.             nrequire(status, failed_global_on);
  499.  
  500.         }//end if
  501.  
  502. failed_undefine:
  503. failed_global_on:
  504. failed_debuggingComment:
  505.  
  506.         if (tagLocked)                        // in case an error happened and we get down here before tag was unlocked in loop.
  507.             GXUnlockTag(infoTag);
  508.         
  509.         return(status);
  510.     
  511.     }//RemoveDownloadedCRDs
  512.